﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Possan.Localization;
using System.Text.RegularExpressions;
using System.IO;
using System.Globalization;

namespace Possan.Localization.Scanner
{
	public class CodeScanner
	{
		ILibraryProvider library;

		public CodeScanner(ILibraryProvider lib)
		{
			library = lib;
		}

		public void ScanCsharpFile(string path)
		{
			string allcode = File.ReadAllText(path);
			ScanCsharpSource(allcode, path);
		}

		public void ScanCsharpSource(string code)
		{
			ScanCsharpSource(code, "");
		}

		string UnescapeCSharpString(string input)
		{
			input = input.Replace("\\\\", "\\");
			input = input.Replace("\\\"", "\"");
			input = input.Replace("\\\'", "\'");
			return input;
		}


		public static string Clean(string code)
		{
			code = RemoveMultilineComments(code);
			code = RemoveUnescapedStrings(code);
			code = RemoveSinglelineComments(code);
			return code;
		}



		public void ScanCsharpSource(string code, string filename)
		{
			code = Clean(code);

			// guess namespace
			string defaultns = "";
			Match mns = Regex.Match(code, @"[\s^]?namespace\s+([a-z0-9_.]+)[\s$]", RegexOptions.IgnoreCase | RegexOptions.Singleline);
			if (mns.Success)
				defaultns = mns.Groups[1].Value;

			// guess class
			string defaultclass = "";
			Match mcl = Regex.Match(code, @"[\s^]?class\s+([a-z0-9_.]+)[\s$]", RegexOptions.IgnoreCase | RegexOptions.Singleline);
			if (mcl.Success)
				defaultclass = mcl.Groups[1].Value;

			string fullns = defaultns + "." + defaultclass;

			Console.WriteLine("Scanning sourcefile \"" + filename + "\" with guessed namespace: " + fullns);

			MatchCollection mc;

			mc = Regex.Matches(code, @"(Translate\.[ID|Phrase].+)$", RegexOptions.Multiline);
			foreach (Match m in mc)
			{
				if (m.Groups.Count > 1)
				{
					string blob = m.Groups[1].Value;
					Console.WriteLine("*** Found blob: " + blob);

					var rowparser = new CSharpRowParser(blob);
					if (rowparser.Parse())
					{
						if (rowparser.FoundID != "")
						{
							if (rowparser.ThisNamespace)
								rowparser.FoundNamespace = fullns;
							else if (!rowparser.FoundNamespace.Contains("."))
								rowparser.FoundNamespace = defaultns + "." + rowparser.FoundNamespace;

							library.RegisterPhraseID(rowparser.FoundNamespace, rowparser.FoundID, rowparser.FoundFallbackPhrase, "", CultureInfo.InvariantCulture);

							Console.WriteLine("Found id \"" + rowparser.FoundID + "\" with phrase \"" + rowparser.FoundFallbackPhrase + "\" in guessed namespace \"" + rowparser.FoundNamespace + "\"");
						}
						else if (rowparser.FoundPhrase != "")
						{

							if (rowparser.ThisNamespace)
								rowparser.FoundNamespace = fullns;
							else if (!rowparser.FoundNamespace.Contains("."))
								rowparser.FoundNamespace = defaultns + "." + rowparser.FoundNamespace;

							library.RegisterPhrase(rowparser.FoundNamespace, rowparser.FoundPhrase, "", CultureInfo.InvariantCulture);

							Console.WriteLine("Found phrase: \"" + rowparser.FoundPhrase + "\" in namespace \"" + rowparser.FoundNamespace + "\"");
						}
					}

					Console.WriteLine();
				}
			}
		}

		public static string RemoveSinglelineComments(string code)
		{
			code = Regex.Replace(code, @"\/\/.*$", "", RegexOptions.IgnoreCase | RegexOptions.Multiline);
			return code;
		}

		public static string RemoveUnescapedStrings(string code)
		{
			string output = "";

			bool in_multilinestring = false;

			int position = 0;
			while (position < code.Length)
			{
				bool passthru = true;// !in_multilinestring;

				char ch = code[position];
				position++;

				char nextchar = '\0';
				if (position < code.Length)
					nextchar = code[position];

				if (ch == '@')
				{
					if (nextchar == '\"')
					{
						//	if (!in_multilinestring)
						//	{
						position++;
						in_multilinestring = true;
						passthru = false;
						//	}
					}
				}
				else if (ch == '\"')
				{
					if (in_multilinestring)
					{
						if (nextchar == '\"')
						{
							// hittar vi två \" efter varan så är det passthru
							// passthru = true;                                
							position+=2;
							passthru = false;
						}
						else
						{
							// om vi hittar ett \" så är det slut på sträng.
							in_multilinestring = false;
						//	position++;
							passthru = false;
						}
					}
				}

				if (passthru && !in_multilinestring)
					output += ch;
			}

			// code = Regex.Replace(code, @"\/\*.*\*\/", "", RegexOptions.IgnoreCase | RegexOptions.Singleline);

			return output;

			// @ "??""?""??"

			// code = Regex.Replace(code, @"@\"".*\""([^\""])", "$1", RegexOptions.IgnoreCase | RegexOptions.Singleline);

			// @".*?(""|[^"])"([^"]|$)
			// code = Regex.Replace(code, "@\\\".*?(\\\"\\\"|[^\\\"])\\\"([^\\\"])", "$2", RegexOptions.IgnoreCase | RegexOptions.Singleline);

			// @"[^"]*?(""[^"]*?)*";
			// code = Regex.Replace(code, "@\\\"([^\\\"]*?(\\\"\\\"[^\\\"]*?)*\\\"|\\\")", "", RegexOptions.IgnoreCase | RegexOptions.Singleline);
			// code = Regex.Replace(code, "@\\\"([^\\\"]*?(\\\"\\\"[^\\\"]*?)*)\\\"", "", RegexOptions.IgnoreCase | RegexOptions.Singleline);

			// @"[^"]*?(""[^"]*?)*"
			//			code = Regex.Replace(code, "@\\\"[^\\\"]*?(\\\"\\\"[^\\\"]*?)*\\\"", "", RegexOptions.IgnoreCase | RegexOptions.Singleline);

			//			return code;
		}

		public static string RemoveMultilineComments(string code)
		{
			string output = "";

			bool in_comment = false;
			bool in_string = false;
			int position = 0;
			while (position < code.Length)
			{
				bool passthru = true;
				char ch = code[position];
				position++;
				if (ch == '\"')
				{
					in_string = !in_string;
				}
				else if (ch == '/')
				{
					char nextchar = code[position];
					if (nextchar == '*')
					{
						if (!in_comment)
						{
							position++;
							in_comment = true;
							passthru = false;
						}
					}
				}
				else if (ch == '*')
				{
					char nextchar = code[position];
					if (nextchar == '/')
					{
						if (in_comment)
						{
							position++;
							in_comment = false;
							passthru = false;
						}
					}
				}

				if (passthru && !in_comment)
					output += ch;
			}

			// code = Regex.Replace(code, @"\/\*.*\*\/", "", RegexOptions.IgnoreCase | RegexOptions.Singleline);

			return output;
		}

	}
}
